var util = require('util');
var fs = require("fs");

var MODNAME = 'Logger';

/*This is the main constructor function */
var Logger = function(pObj) {
	console.log("... Created Logger Object "+pObj);
	
	this.OUTPUT_MODE = 'CONSOLE'; //['CONSOLE', 'FILE'];
	this.TRACE_OPTIONS = {
			'TRACE_HEADER'		:	'MMT',			
			'CUR_TRACE_LEVEL'	:	0,
			'TRACE_MODE'		:	1,
			
			'INFO_LEVEL_1'		:	0, //BASIC
			'INFO_LEVEL_2'		:	0, //FUNC PARAMS
			'INFO_LEVEL_3'		:	0, //DETAILS
			'INFO_LEVEL_4'		:	0,
			'INFO_LEVEL_5'		:	0,
			'INFO_LEVEL_6'		:	0, //LONGDESC
			'ERROR'				:	0,
			'WARNING'			:	0,
			
	};	
	
	this.loadTraceOptions(pObj);
	
	if (this.OUTPUT_MODE === 'FILE') {
		this.node_traces_fd = fs.openSync('./node_traces.out', 'a');
		//fs.closeSync(node_traces_fd);
	}
};
/**
 * Is used to generate string with the given char
 * @param len		int,	length
 * @param char		char,	character to be repeated
 * @returns			string,	Result
 */
function makeStr(len, ch) {
    return Array.prototype.join.call({length: (len || -1) + 1}, ch || 'x');
}
Logger.prototype.log = function(pModName, pTraceOption, pMsg) {
	//console.log(Logger.TRACE_OPTIONS);
	if(!this.TRACE_OPTIONS.hasOwnProperty(pTraceOption)) throw "Invalid TraceOption ["+pTraceOption+"]";
	
	if (this.TRACE_OPTIONS[pTraceOption]){
		if(typeof pMsg === 'object') {
			pMsg = util.inspect(pMsg);
		}
		
		var prefix = '';
		if ('INFO_LEVEL_1' === pTraceOption) prefix = makeStr(1,'.');
		if ('INFO_LEVEL_2' === pTraceOption) prefix = makeStr(2,'.');
		if ('INFO_LEVEL_3' === pTraceOption) prefix = makeStr(3,'.');
		
		if ('INFO_LEVEL_4' === pTraceOption) prefix = makeStr(4,'.');
		if ('INFO_LEVEL_5' === pTraceOption) prefix = makeStr(5,'.');
		if ('INFO_LEVEL_6' === pTraceOption) prefix = makeStr(6,'.');
		
		var output = util.format('%s: %s %s %s [%s] %s', this.TRACE_OPTIONS.TRACE_HEADER, getTime(), pTraceOption, prefix, pModName, pMsg);
		if (this.OUTPUT_MODE === 'FILE') {
			var buffer = new Buffer(output + '\n');
			if (this.node_traces_fd)
				fs.writeSync(this.node_traces_fd, buffer, 0, buffer.length, null);
		}
		
		if ('ERROR' === pTraceOption) {
			console.error(output);
		} else if ('WARNING' === pTraceOption) {
			console.warn(output);
		} else {			
			console.info(output);
		}		
	}
		
}

function getTime() {
	var d = new Date();
	return util.format('%s:%s:%s:%s', d.getHours(), d.getMinutes(), d.getSeconds(), d.getMilliseconds());
}
Logger.prototype.getTraceOptions = function () {
	return this.TRACE_OPTIONS;
};
Logger.prototype.getCurTRACELEVEL = function () {
	var traceOptions = this.getTraceOptions();
	//console.log(traceOptions.CUR_TRACE_LEVEL);
	return traceOptions.CUR_TRACE_LEVEL;
};

Logger.prototype.close = function() {
	fs.closeSync(this.node_traces_fd);
};
Logger.prototype.loadTraceOptions = function(pObj) {
	
	var TRACELEVEL = 1;
	
	if (pObj) {
		if (pObj.hasOwnProperty('TRACELEVEL'))
			TRACELEVEL = pObj.TRACELEVEL;			
		
		if (pObj.hasOwnProperty('MODE')) 
			this.TRACE_OPTIONS.TRACE_MODE = pObj.MODE;
	}	
	
	var num = parseInt(TRACELEVEL);
	if (num > 255) throw "Invalid TRACELEVEL";
	
	//if (bits.status(num,0)) always visible
	this.TRACE_OPTIONS.INFO_LEVEL_1 = 0;
	this.TRACE_OPTIONS.INFO_LEVEL_2 = 0;
	this.TRACE_OPTIONS.INFO_LEVEL_3 = 0;
	
	this.TRACE_OPTIONS.INFO_LEVEL_4 = 0;
	this.TRACE_OPTIONS.INFO_LEVEL_5 = 0;
	this.TRACE_OPTIONS.INFO_LEVEL_6 = 0;
	this.TRACE_OPTIONS.ERROR = 0;
	this.TRACE_OPTIONS.WARNING = 0;
	
	if (bits.status(num,0)) this.TRACE_OPTIONS.INFO_LEVEL_1 = 1;
	if (bits.status(num,1)) this.TRACE_OPTIONS.INFO_LEVEL_2 = 1;
	if (bits.status(num,2)) this.TRACE_OPTIONS.INFO_LEVEL_3 = 1;
	if (bits.status(num,3)) this.TRACE_OPTIONS.INFO_LEVEL_4 = 1;
	
	if (bits.status(num,4)) this.TRACE_OPTIONS.INFO_LEVEL_5 = 1;
	if (bits.status(num,5)) this.TRACE_OPTIONS.INFO_LEVEL_6 = 1;
	if (bits.status(num,6)) this.TRACE_OPTIONS.ERROR = 1;
	if (bits.status(num,7)) this.TRACE_OPTIONS.WARNING = 1;
	
	this.TRACE_OPTIONS.CUR_TRACE_LEVEL = num;
	this.log(MODNAME, 'INFO_LEVEL_1', 'Current [TRACEMODE] = '+this.TRACE_OPTIONS.TRACE_MODE+', [TRACELEVEL] = ' + this.TRACE_OPTIONS.CUR_TRACE_LEVEL);
}


//print ModuleName, functionname, LINENUMBER, input params, output params
var bits ={
	'status': function(num,bit) {
		//console.log(num.toString(2));		
	    return ((num>>bit) % 2 != 0);
	},
	'set': function(num,bit){
	    return num | 1<<bit;
	},
	'clear': function(num,bit){
	    return num & ~(1<<bit);
	},
	'toggle': function(num,bit){
	    return bit_test(num,bit)?bit_clear(num,bit):bit_set(num,bit);
	}
};

//module.exports = function(pObj) { return new Logger(pObj); };
exports.create = function(pObj) { return new Logger(pObj); };

/*

var obj = {TRACELEVEL: 1};
var loggerobj = new Logger(obj);
console.log(loggerobj.getTraceOptions());
loggerobj.loadTraceOptions({TRACELEVEL: 255});
console.log(loggerobj.getTraceOptions());
loggerobj.log('INFO_LEVEL_1','hi');
*/